package node.decl;

import grammar.Lexer;
import grammar.MyError;
import lexical.Key;
import lexical.Word;
import midcode.MidCode;
import midcode.MidcodeGenerator;
import midcode.OPType;
import node.Node;
import node.exp.ConstExp;
import symbol.Symbol;
import symbol.SymbolTable;

import java.util.ArrayList;

public class ConstDef implements Node{
    private final Lexer lexer;
    private final SymbolTable table;
    private final Node father;
    private Symbol symbol;
    private ConstInitVal constInitVal;
    private int dim = 0;
    private ArrayList<Node> nodes = new ArrayList<>();
    private ArrayList<ConstExp> exps = new ArrayList<>();

    public ConstDef(Lexer lexer, SymbolTable table, Node father) {
        this.lexer = lexer;
        this.table = table;
        this.father = father;
        parseConstDef();
    }

    private void parseConstDef() {
        Word word = lexer.getWord(0);
        nodes.add(lexer.getCurWord()); // ident
        while (lexer.isWordType(0, Key.LBRACK)) {
            dim++;
            nodes.add(lexer.getCurWord()); // [
            ConstExp exp = new ConstExp(lexer, table, this);
            nodes.add(exp);
            exps.add(exp);
            if (lexer.isWordType(0, Key.RBRACK)) {
                nodes.add(lexer.getCurWord()); // ]
            } else {
                lexer.addError(new MyError(lexer.getWord(-1).lineNum, 'k'));
            }
        }
        if (table.redefine(word.word)) {
            lexer.addError(new MyError(word.lineNum, 'b')); // error b
        }
        symbol = new Symbol("const", dim, word, table.getSymbolId());
        table.addSymbol(symbol);
        nodes.add(lexer.getCurWord()); // =
        constInitVal = new ConstInitVal(lexer, table, this, dim);
        nodes.add(constInitVal);
    }

    private void setSymbolValue(boolean isGlobal) {
        if (dim == 0) {
            symbol.setVal_0(constInitVal.getVal_0());
        } else if (dim == 1) {
            symbol.setVal_1(constInitVal.getVal_1());
        } else {
            symbol.setVal_2(constInitVal.getVal_2());
        }
        symbol.setSize();
        if (isGlobal) {
            symbol.setOffset_gp();
        }
    }

    @Override
    public Node getFather() {
        return father;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (Node word : nodes) {
            sb.append(word.toString());
        }
        return sb.append("<ConstDef>\n").toString();
    }

    @Override
    public String genMidCode() {
        MidcodeGenerator mg = MidcodeGenerator.getInstance();
        if (mg.getFuncName().equals("global")) {       //全局变量
            setSymbolValue(true);
            mg.addGlobalDecl(new MidCode(OPType.GLOBAL_VAL, null, null, symbol.getName()));
        } else {                                        //局部变量
            setSymbolValue(false);
            if (dim == 0) {
                mg.addMidcode(new MidCode(OPType.ASSIGN, symbol.getName(), null, Integer.toString(symbol.getVal_0())));
            } else if (dim == 1) {
                int i = 0;
                for (Integer val : symbol.getVal_1()) {
                    mg.addMidcode(new MidCode(OPType.SW_ARRAY, symbol.getName(), Integer.toString(i++), Integer.toString(val)));
                }
            } else {
                int i = 0;
                for (ArrayList<Integer> list : symbol.getVal_2()) {
                    for (Integer val : list) {
                        mg.addMidcode(new MidCode(OPType.SW_ARRAY, symbol.getName(), Integer.toString(i++), Integer.toString(val)));
                    }
                }
            }
        }
        return "";
    }
}
